package com.pl.interceptor;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.logging.Handler;

/**
 * 拦截器的原理很简单，是 AOP 的一种实现，
 * 专门拦截对动态资源的后台请求，即拦截对控制层的请求。
 * 使用场景比较多的是判断用户是否有权限请求后台，
 * 更拔高一层的使用场景也有，比如拦截器可以结合 websocket 一起使用，
 * 用来拦截 websocket 请求，然后做相应的处理等等。
 * 拦截器不会拦截静态资源，Spring Boot 的默认静态目录为 resources/static，
 * 该目录下的静态页面、js、css、图片等等，不会被拦截（也要看如何实现，有些情况也会拦截）
 * <p>
 * 定义拦截器，只需要实现 HandlerInterceptor 接口，
 * HandlerInterceptor 接口是所有自定义拦截器或者 Spring Boot 提供的拦截器的鼻祖，
 * 该接口中有三个方法： preHandle(……)、postHandle(……) 和 afterCompletion(……) 。
 * <p>
 * 1.preHandle(……) 方法：该方法的执行时机是，
 * 当某个 url 已经匹配到对应的 Controller 中的某个方法，
 * 且在这个方法执行之前。所以 preHandle(……) 方法可以决定是否将请求放行，
 * 这是通过返回值来决定的，返回 true 则放行，返回 false 则不会向后执行。
 * 2.postHandle(……) 方法：该方法的执行时机是，
 * 当某个 url 已经匹配到对应的 Controller 中的某个方法，
 * 且在执行完了该方法，但是在 DispatcherServlet 视图渲染之前。
 * 所以在这个方法中有个 ModelAndView 参数，可以在此做一些修改动作。
 * 3.afterCompletion(……) 方法：顾名思义，
 * 该方法是在整个请求处理完成后（包括视图渲染）执行，
 * 这时做一些资源的清理工作，
 * 这个方法只有在 preHandle(……) 被成功执行后并且返回 true 才会被执行。
 *
 * @author shent
 */
public class MyInterceptor implements HandlerInterceptor {
    private static final Logger logger = LoggerFactory.getLogger(MyInterceptor.class);

    /**
     * 访问系统内的接口前,先判断用户有没有登录
     *
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (handler instanceof HandlerMethod) {
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            Method method = handlerMethod.getMethod();
            String methodName = method.getName();
            logger.info("====拦截到了方法：{}，在该方法执行之前执行====", methodName);

            // 1.判断用户有没有登陆，一般登陆之后的用户都有一个对应的token
        /*String token = request.getParameter("token");
        if (null == token || "".equals(token)) {
            logger.info("用户未登录，没有权限执行……请登录");
            return false;
        }*/

            // 2.通过方法，可以获取该方法上的自定义注解，然后通过注解来判断该方法是否要被拦截
            // @UnInterception 是我们自定义的注解
            UnInterception unInterception = method.getAnnotation(UnInterception.class);
            if (null != unInterception) {
                return true;
            }
        }
        // 返回true才会继续执行，返回false则取消当前请求
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        logger.info("执行完方法之后进执行(Controller方法调用之后)，但是此时还没进行视图渲染");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        logger.info("整个请求都处理完咯，DispatcherServlet也渲染了对应的视图咯，此时我可以做一些清理的工作了");
    }
}
